#ifndef __M_ROUTE_H__
#define __M_ROUTE_H__
#include <iostream>
#include "../mqcommon/mq_loger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include "../mqcommon/mq_helper.hpp"


namespace mq{

class Router{
public:
    static bool isLegalRoutingKey(const std::string& routing_key){
        for(auto& c : routing_key){
            if((c > '0' && c < '9') || (c > 'A' && c < 'z') || c == '_' || c == '.'){
                //进来代表正常则继续
                continue;
            }
            //没进去则代表不符合条件

            DLOG("routing_key:%s,不合法字符为：%c",routing_key.c_str(),c);
            return false;
        }
        return true;
    }

    
    static bool isLegalBindingKey(const std::string& binding_key){
        for(auto& c : binding_key){
            if((c > '0' && c < '9') || (c > 'A' && c < 'z') || c == '_' || c == '.' || c == '#' || c == '*'){
                //进来代表正常则继续
                continue;
            }
            //没进去则代表不符合条件
                
            DLOG("binding_key:%s,不合法字符为：%c",binding_key.c_str(),c);
            return false;
        }

        //* 和 # 必须独立出现,类似这种就是错的：news.music#.pop.# (其中music#就是错的)
        std::vector<std::string> vs;
        mqhelper::StrHelper().split(binding_key,".",vs);
        for(auto& s : vs){
        //    std::cout << s << std::endl;
            if(s.size() > 1 && s.find('#') != -1 && s.find('#') != 0 ||  s.find('*') != -1 &&  s.find('*') != 0 ){
                DLOG("binding_key:%s不合法,通配符没有独立出现",binding_key.c_str());
                return false;
            }
        }
        
        //* 和 # 不能连续出现
        for(int i = 1 ; i < vs.size();i++){
            
            if((vs[i] == "*" && vs[i-1] == "#"  ) ||( vs[i] == "#" && (vs[i-1] == "*" || vs[i-1] == "#"))){

                    DLOG("binding_key:%s不合法，通配符不能连续出现",binding_key.c_str());
                    return false;
            }
        }

        return true;
    }

    static bool route(mq::ExchangeType type,const std::string& routing_key,const std::string& binding_key){
        if(!isLegalRoutingKey(routing_key) || !isLegalBindingKey(binding_key)){
            return false;
        }
        
        if(type == mq::ExchangeType::DIRECT){
            //交换机类型为 直接交换，则直接判断 r 和 b 是否相等
            // DLOG("DIRECT");
           return routing_key == binding_key;
      
        }
        else if(type == mq::ExchangeType::FANOUT){
            // DLOG("FANOUT");

            //交换机类型：广播交换，则全部返回真
            return true;
        }

        // DLOG("TOPIC");
        //若前两个都不是则表示交换机类型为：主题交换
        //通过动态规划的方式进行规则匹配

        //1. 先将routing_key和binding_key分割出一个个小字符串，进行规则匹配
        std::vector<std::string> rkeys,bkeys;
        int n_rkey = mqhelper::StrHelper().split(routing_key,".",rkeys);
        int n_bkey = mqhelper::StrHelper().split(binding_key,".",bkeys);
        // cout << " routing_key:" << routing_key << "binding_key" << binding_key<< "n_rkey:"<< n_rkey << "n_bkey:" << n_bkey << endl;
        //2. 创建dp，大小为长为rkeys大小+1 宽为 bkeys+1，并先将所有都置为false
        std::vector<std::vector<bool>> dp(n_bkey+1,std::vector<bool>(n_rkey+1,false));
        
        // for (int i = 0; i <= bkeys.size(); ++i) {
        //     for (int j = 0; j <= rkeys.size(); ++j) {
        //         std::cout << dp[i][j] << " ";
        //     }
        //     std::cout << std::endl;
        // }
        // DLOG("bingding_key小字符串长度:%d,routing_key小字符串长度:%d",n_bkey,n_rkey);

        //3. 提前处理dp数组
            //1. 默认将 00 位置处置为true
        dp[0][0] = true;
            //2. 判断# 是否出现在前面，若出现了前面则将# 对应行的首列置为true
        for(int i = 1 ; i <= n_bkey;i++){
             if (bkeys[i - 1] == "#") {
                        dp[i][0] = true;
                        continue;
                }
            break;
        }

        //4. 进行匹配规则
        for(int i = 1;i <= n_bkey;i++)
        {
            for(int j = 1;j <= n_rkey;j++)
            {
                // DLOG("开始匹配,i：%d,j：%d",i,j);
                if(bkeys[i-1] == "*" || bkeys[i-1] == rkeys[j-1]){
                    dp[i][j] = dp[i-1][j-1];//若正常匹配成功，则直接从左上角继承
                }
                if(bkeys[i-1] == "#"){
                    dp[i][j] = dp[i-1][j-1] || dp[i][j-1] || dp[i-1][j];
                }

                // DLOG("r:%s,b:%s,匹配值：%d",rkeys[j-1].c_str(),bkeys[i-1].c_str(),dp[i][j]);
            }
        }
        bool ret = dp[n_bkey][n_rkey];
        // DLOG("匹配结果：%s",ret ? "true" : "false");
        // for (int i = 0; i <= bkeys.size(); ++i) {
        //     for (int j = 0; j <= rkeys.size(); ++j) {
        //         std::cout << dp[i][j] << " ";
        //     }
        //     std::cout << std::endl;
        // }
        return ret;
    }
};
}
#endif